package com.fintech.pangu.config;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.fintech.pangu.generator.constant.DBConstant;
import com.fintech.pangu.generator.constant.FieldConst;
import com.fintech.pangu.generator.entity.TableFieldExtend;
import com.fintech.pangu.generator.entity.TableGeneratorConfig;
import com.fintech.pangu.generator.util.FontUtil;
import com.fintech.pangu.generator.util.GeneratorUtil;
import org.springframework.core.io.ClassPathResource;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: 输入参数配置
 * @Author xiexiaole
 * @Date 2019/12/3 11:16
 */
public class ParamConfig extends InjectionConfig {

    private static final String PATH_TEMPLATE = "/templates/";
    private static final String PATH_JAVA = "/src/main/java/";
    private static final String PATH_RESOURCES = "/src/main/resources/";
    private String outPath;
    private String basePath;

    private String dataSourceUrl;
    private String dataSourceUserName;
    private String dataSourcePassword;

    private List  tableList = new ArrayList();
    private String pathPackage;
    private String artifactId;
    private String basePackage;
    private String author;
    private String description;
    private String version;
    private String parentVersion;

    private Map<String,TableGeneratorConfig> tableExtendMap;


    public ParamConfig(JSONObject jsonParams, String basePath, String version) {
        this.basePath = basePath;
        //数据源
        JSONObject dataSource = jsonParams.getJSONObject(FieldConst.DATA_SOURCE);
        this.dataSourceUrl = dataSource.getString(FieldConst.DATA_SOURCE_URL);
        this.dataSourceUserName = dataSource.getString(FieldConst.DATA_SOURCE_USER_NAME);
        this.dataSourcePassword = dataSource.getString(FieldConst.DATA_SOURCE_PASSWORD);

        //基础配置
        JSONObject baseConfig = jsonParams.getJSONObject(FieldConst.BASE_CONFIG);
        this.basePackage = baseConfig.getString(FieldConst.BASE_PACKAGE);
        this.artifactId = baseConfig.getString(FieldConst.ARTIFACT);
        this.pathPackage = basePackage.replace(".","/");
        this.outPath = basePath+ artifactId;
        this.author = baseConfig.getString(FieldConst.AUTHOR);
        this.description = baseConfig.getString(FieldConst.DESCRIPTION);
        this.version = version;
        this.parentVersion = baseConfig.getString(FieldConst.PARENTVERSION);

        //tableList
        this.tableExtendMap = new HashMap<>();
        JSONArray tableList = jsonParams.getJSONArray(FieldConst.TABLE_LIST);
        for (int i = 0; i < tableList.size(); i++) {
            JSONObject table = tableList.getJSONObject(i);
            String tableName = table.getString(FieldConst.TABLE_NAME);
            JSONArray fieldList = table.getJSONArray(FieldConst.FIELDS);
            TableGeneratorConfig tableConfig = new TableGeneratorConfig();
            tableConfig.setTableName(tableName);
            for (int j = 0; j < fieldList.size(); j++) {
                JSONObject field = fieldList.getJSONObject(j);
                String fieldName = field.getString(FieldConst.FIELD_NAME);
                Integer fetch = field.getInteger(FieldConst.FETCH);
                Integer createUpdate = field.getInteger(FieldConst.CREATE_UPDATE);
                Integer vo = field.getInteger(FieldConst.VO);
                tableConfig.addFetchGeneratorColumn(fieldName,fetch);
                tableConfig.addCuGeneratorColumn(fieldName,createUpdate);
                tableConfig.addVoGeneratorColumn(fieldName, vo);
            }
            tableExtendMap.put(tableName,tableConfig);
            this.tableList.add(tableName);
        }
    }

    public DataSourceConfig getDataSourceConfig(){
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDbType(DbType.MYSQL);
        dataSourceConfig.setDriverName(DBConstant.DB_DRIVER_NAME);
        dataSourceConfig.setUrl(dataSourceUrl);
        dataSourceConfig.setUsername(dataSourceUserName);
        dataSourceConfig.setPassword(dataSourcePassword);
        return dataSourceConfig;
    }

    public GlobalConfig getGlobalConfig(){
        GlobalConfig globalConfig = new GlobalConfig();
        //输出目录
        globalConfig.setOutputDir(basePath);
        // 是否覆盖文件
        globalConfig.setFileOverride(true);
        // 开启 activeRecord 模式
        globalConfig.setActiveRecord(false);
        // XML 二级缓存
        globalConfig.setEnableCache(false);
        // XML ResultMap
        globalConfig.setBaseResultMap(true);
        // XML columList
        globalConfig.setBaseColumnList(true);
        globalConfig.setDateType(DateType.SQL_PACK);
        //生成后打开文件夹
        globalConfig.setOpen(false);
        globalConfig.setAuthor(author);
        // 自定义文件命名，注意 %s 会自动填充表实体属性！
        globalConfig.setMapperName("%sDao");
        globalConfig.setXmlName("%sMapper");
        globalConfig.setServiceName("%sService");
        globalConfig.setServiceImplName("%sServiceImpl");
        globalConfig.setControllerName("%sController");
        return globalConfig;
    }

    public StrategyConfig getStrategyConfig(){
        StrategyConfig strategyConfig = new StrategyConfig();
        // 全局大写命名
        strategyConfig.setCapitalMode(false);
        //.setTablePrefix(new String[]{prefix})// 此处可以修改为您的表前缀
        // 表名生成策略
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        // 需要生成的表
        String [] tableArr = new String[tableList.size()];
        tableList.toArray(tableArr);
        strategyConfig.setInclude(tableArr);
        strategyConfig.setRestControllerStyle(true);
        strategyConfig.setEntityTableFieldAnnotationEnable(true);
        //.setTablePrefix("sys_")
        strategyConfig.setEntityColumnConstant(false);
        // 【实体】是否为构建者模型（默认 false）
        // public User setName(String name) {this.name = name; return this;}
        strategyConfig.setEntityBuilderModel(true);
        // 【实体】是否为lombok模型（默认 false）<a href="https://projectlombok.org/">document</a>
        strategyConfig.setEntityLombokModel(true);
        // Boolean类型字段是否移除is前缀处理
        // .setEntityBooleanColumnRemoveIsPrefix(true)
        // 生成 @RestController 控制器
        strategyConfig.setRestControllerStyle(true);
        // 驼峰转连字符
        strategyConfig.setControllerMappingHyphenStyle(false);
        return strategyConfig;
    }

    public PackageConfig getPackageInfo(){
        String serviceSubName = artifactId + "-service";
        HashMap<String, String> map = new HashMap<>();
        map.put(ConstVal.ENTITY_PATH, outPath + "/" + serviceSubName + PATH_JAVA + pathPackage + "/web/entity");
        map.put(ConstVal.MAPPER_PATH, outPath + "/" + serviceSubName + PATH_JAVA + pathPackage + "/web/dao");
        map.put(ConstVal.SERVICE_PATH, outPath + "/" + serviceSubName + PATH_JAVA + pathPackage + "/web/service");
        map.put(ConstVal.SERVICE_IMPL_PATH, outPath + "/" + serviceSubName + PATH_JAVA + pathPackage + "/web/service/impl");
        map.put(ConstVal.CONTROLLER_PATH, outPath + "/" + serviceSubName + PATH_JAVA + pathPackage + "/web/controller");
        PackageConfig packageConfig = new PackageConfig()
                .setPathInfo(map)
                .setModuleName(null)
                // 自定义包路径
                .setParent(basePackage + ".web")
                // 这里是控制器包名，默认 web
                .setController("controller")
                .setEntity("entity")
                .setMapper("dao")
                .setService("service")
                .setServiceImpl("service.impl")
                .setXml("mapper");

        return packageConfig;
    }

    public TemplateConfig getTemplateConfig(){
        // 关闭默认 xml 生成，调整生成 至 根目录
        TemplateConfig templateConfig = new TemplateConfig().setXml(null);
        return templateConfig;
    }

    public String getOutPath(){
        return outPath;
    }

    @Override
    public List<FileOutConfig> getFileOutConfigList() {
        //自定义文件输出位置
        List<FileOutConfig> fileOutList = new ArrayList<FileOutConfig>();
        //模块pom
        FileOutConfig rootPom = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "root.pom.ftl", outPath + "/pom.xml");
        fileOutList.add(rootPom);

        /** api模块 */
        // api-qo
        String apiSubName = artifactId + "-api";
        FileOutConfig apiQO = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "cu.java.ftl",
                outPath + "/" + apiSubName + PATH_JAVA + pathPackage + "/api/bean/qo/CreateAndModify{0}Request" + ".java");
        fileOutList.add(apiQO);

        //api-fetch
        FileOutConfig apiFetch = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "fetch.java.ftl",
                outPath + "/" + apiSubName + PATH_JAVA + pathPackage + "/api/bean/qo/Fetch{0}Request" + ".java");
        fileOutList.add(apiFetch);

        //api-vo
        FileOutConfig apiVO = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "vo.java.ftl",
                outPath + "/" + apiSubName + PATH_JAVA + pathPackage + "/api/bean/vo/{0}Result" + ".java");
        fileOutList.add(apiVO);

        //api-interface
        FileOutConfig apiInterface = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "controllerApi.java.ftl",
                outPath + "/" + apiSubName + PATH_JAVA + pathPackage + "/api/interfaces/I{0}Api.java");
        fileOutList.add(apiInterface);

        //api-pom
        FileOutConfig apiPom = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "api.pom.ftl",
                outPath + "/" + apiSubName + "/pom.xml");
        fileOutList.add(apiPom);
        /** feign */
        //feign-feign
        String feignSubName = artifactId + "-feign";
        FileOutConfig feign = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "feign.java.ftl",
                outPath + "/" + feignSubName + PATH_JAVA + pathPackage + "feign/I{0}Feign.java");
        fileOutList.add(feign);

        // feign-pom
        FileOutConfig feignPom = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "feign.pom.ftl",
                outPath + "/" + feignSubName + "/pom.xml");
        fileOutList.add(feignPom);
        /** service */
        String serviceSubName = artifactId + "-service";

        // service-mapper.xml
        FileOutConfig serviceMapper = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "mapper.xml.ftl",
                outPath + "/" + serviceSubName + PATH_RESOURCES + "/mappers/{0}Dao" + ".xml");
        fileOutList.add(serviceMapper);

        // service-dto
        FileOutConfig serviceDTO = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "dto.java.ftl",
                outPath + "/" + serviceSubName + PATH_JAVA + pathPackage + "/web/dto/{0}Dto" + ".java");
        fileOutList.add(serviceDTO);

        // service-transform
        FileOutConfig serviceTransform = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "transform.java.ftl",
                outPath + "/" + serviceSubName + PATH_JAVA + pathPackage + "/web/mapper/{0}Mapper.java");
        fileOutList.add(serviceTransform);

        // service-pom
        FileOutConfig servicePom = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "service.pom.ftl",
                outPath + "/" + serviceSubName + "/pom.xml");
        fileOutList.add(servicePom);

        // service-application.properties
        FileOutConfig serviceAppProp = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "application.properties.ftl",
                outPath + "/" + serviceSubName + PATH_RESOURCES + "application.properties");
        fileOutList.add(serviceAppProp);

        // service-logback-spring.xml
        FileOutConfig serviceLogback = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "logback-spring.xml.ftl",
                outPath + "/" + serviceSubName + PATH_RESOURCES + "logback-spring.xml");
        fileOutList.add(serviceLogback);

        // service-application.java 启动类
        FileOutConfig serviceAppStart = GeneratorUtil.getOutConfig(PATH_TEMPLATE + "application.java.ftl",
                outPath + "/" + serviceSubName + PATH_JAVA + pathPackage + "/ServiceApplication.java");
        fileOutList.add(serviceAppStart);

        // service-config
        String configOutPath = outPath + "/" + serviceSubName + PATH_JAVA + pathPackage + "/config/";
        try {
            ClassPathResource classPathResource = new ClassPathResource("templates/config");
            InputStream inputStream = classPathResource.getInputStream();
            byte[] bit = new byte[inputStream.available()];
            inputStream.read(bit);
            String[] split = new String(bit).split("\n");
            for (String name : split) {
                int i = name.lastIndexOf(".");
                String className = name.substring(0, i);
                fileOutList.add(new FileOutConfig(PATH_TEMPLATE + "config/" + name) {
                    @Override
                    public String outputFile(TableInfo tableInfo) {
                        tableInfo.setConvert(true);
                        return configOutPath + className;
                    }
                });
            }
        }catch (Exception e){}

        return fileOutList;
    }

    @Override
    public void initMap() {
        Map<String, Object> map = new HashMap<>();
        Map dataSourceMap = new HashMap();
        dataSourceMap.put("url", dataSourceUrl);
        dataSourceMap.put("userName", dataSourceUserName);
        dataSourceMap.put("password", dataSourcePassword);
        map.put("dataSource", dataSourceMap);
        Map<String, String> params = new HashMap<>();
        params.put("artifactId", artifactId);

        params.put("description", description);
        params.put("descriptionUnicode", FontUtil.chinese2Unicode(description));

        params.put("version", version);
        params.put("parentVersion", parentVersion);
        params.put("basePackage", basePackage);
        map.put("customConfig", params);

        map.putAll(tableExtendMap);
        this.setMap(map);
    }

    @Override
    public Map<String, Object> prepareObjectMap(Map<String, Object> objectMap) {
        TableInfo table = (TableInfo) objectMap.get("table");
        String name = table.getName();
        Map<String, Object> map = getMap();
        TableGeneratorConfig tableConfig = (TableGeneratorConfig)map.get(name);
        if(tableConfig != null) {
            List<TableField> fields = table.getFields();
            List<TableField> tableFieldExtendList = new ArrayList<>();
            for (TableField field : fields) {
                TableFieldExtend fieldExtend = GeneratorUtil.convertTable(field, tableConfig);
                tableFieldExtendList.add(fieldExtend);
            }
            table.setFields(tableFieldExtendList);
        }
        return objectMap;
    }
}
